﻿/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-19
  File:    DispatchTable.cs  
  Description: 
    Implementation of the process dispatch table.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SL.M.Collections
{
    /// <summary>
    /// Represent a dispatch table for message handling.
    /// </summary>
    public class DispatchTable : ICollection<DispatchEntry>
    {
        List<DispatchEntry> _entries = new List<DispatchEntry>();

        /// <summary>
        /// Return a count of entries in the dispatch table.
        /// </summary>
        public int Count
        {
            get
            {
                return _entries.Count;
            }
        }

        /// <summary>
        /// Return if the collection is read only.
        /// </summary>
        /// <remarks>A dispatch table is not read only, and may be modified during execution.</remarks>
        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Add an entry to the collection.
        /// </summary>
        /// <param name="item">The entry to add.</param>
        public void Add(DispatchEntry item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            _entries.Add(item);
        }

        /// <summary>
        /// Clear the collection.
        /// </summary>
        public void Clear()
        {
            _entries.Clear();
        }

        /// <summary>
        /// Return if the table contains the specified item.
        /// </summary>
        /// <param name="item">The item to compare.</param>
        /// <returns>True if the collection contains the specified item.</returns>
        /// <remarks>The target part of the entry is ignored when comparing values in the table.</remarks>
        public bool Contains(DispatchEntry item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            return _entries.Contains(item);
        }

        /// <summary>
        /// Copy the collection to an array.
        /// </summary>
        /// <param name="array">The array to copy into.</param>
        /// <param name="arrayIndex">The index to start copying at.</param>
        public void CopyTo(DispatchEntry[] array, int arrayIndex)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }

            if (arrayIndex < 0 || arrayIndex >= array.Length)
            {
                throw new IndexOutOfRangeException();
            }

            int idx = arrayIndex;
            foreach (DispatchEntry entry in this)
            {
                array[idx] = entry;
                ++idx;
            }
        }

        /// <summary>
        /// Return an enumerator for this collection.
        /// </summary>
        /// <returns>An enumerator.</returns>
        public IEnumerator<DispatchEntry> GetEnumerator()
        {
            return _entries.GetEnumerator();
        }

        /// <summary>
        /// Remove an item from this collection.
        /// </summary>
        /// <param name="item">The item to remove.</param>
        /// <returns>True if the item was removed.</returns>
        /// <remarks>The target part of the entry is ignored when comparing values in the table.</remarks>
        public bool Remove(DispatchEntry item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            return _entries.Remove(item);
        }

        /// <summary>
        /// Return an enumerator for this collection.
        /// </summary>
        /// <returns>An enumerator.</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator<DispatchEntry>)GetEnumerator();
        }

        /// <summary>
        /// Dispatch a message.
        /// </summary>
        /// <param name="message">The message to dispatch.</param>
        /// <returns>True if the message was handled.</returns>
        public bool Dispatch(Message message)
        {
            foreach (DispatchEntry entry in _entries)
            {
                if (message.TypeEquals(entry.Key.Message) && entry.Key.Source.Matches(message.Sender))
                {
                    return entry.Target(message.Data);
                }
            }
            return false;
        }
    }
}
